home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 June: Reference Library / Dev.CD Jun 00 RL Disk 1.toast / pc / technical documentation / develop / develop issue 28 / develop issue 28 code / sketch / source / adts / elementadt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-24  |  36.2 KB  |  1,221 lines

  1. /*********************************************************************************************************************************
  2.  * 
  3.  * ElementADT.c
  4.  * 
  5.  * Functions related to the Element Abstract Data Type
  6.  *
  7.  * Theory of Operation:
  8.  *
  9.  *        The public functions allocate and deallocate memory for the in-memory storage of 
  10.  *        the data necessary to represent an element. Public functions call private (file static) 
  11.  *        functions to maintain a linked list of elements.
  12.  *        
  13.  *        The public functions also provide an iterator service that can be used by the client
  14.  *     to retrieve element references from the linked list.
  15.  *        
  16.  *        The public function ElementError can be used to retrieve any potential error code 
  17.  *        generated by the most recent public function called by the client.
  18.  *
  19.  *        IMPORTANT DEFINITIONS:
  20.  *       Element List  - a doubly-linked list consisting of a head node plus zero or more elements
  21.  *                              - elements in a list are completely maintained by this code
  22.  *                              - destroying an list destroys all its elements.
  23.  *                              - an element can be removed from its list, and is then called an orphan
  24.  *                              - an element has a subelement list, which is used to implement groups
  25.  *
  26.  *            Element Chain - a doubly-linked list consisting of one or more elements, called orphans
  27.  *                     - a chain is not connected to a head node nor to any Element List.
  28.  *                              - the user is responsible for destroying orphaned elements
  29.  *                       by calling FreeOrphanChain(headOfChain);
  30.  *
  31.  * 
  32.  *********************************************************************************************************************************/
  33. #include <string.h>
  34.  
  35. #include "Structs.h"
  36.  
  37. #include "ElementADT.h"
  38. #include "ElementHelpers.h"
  39.  
  40. #include "Assertion.h"
  41.  
  42. #define kLockElementReferences false
  43.  
  44. // ------------------------------------------------------------------------------------------------
  45.  
  46. static OSErr                        fgError                                    = noErr;
  47. static Rect                         fgEmptyRect                                = {0, 0, 0, 0};
  48. static Point                        fgEmptyPoint                            = {0, 0};
  49. static unsigned long                fgElementCount                            = 0;
  50. static unsigned long                fgElementNumber                        = 0;
  51.  
  52. // ------------------------------------------------------------------------------------------------
  53.  
  54. static OSErr                        CreateElementData                        (ElementReference element, ElementType type);
  55. static OSErr                        CloneElementData                        (ElementReference element, ElementReference clone);
  56. static void                         FreeElementData                        (ElementReference element);
  57. static void                         FreeElement                                (ElementReference element);
  58. static void                         Insert                                    (ElementList list, ElementReference element);
  59. static void                         Remove                                    (ElementReference element);
  60. static void                         Link                                        (ElementReference previous, ElementReference next);
  61.  
  62. static Boolean                     ElementListIsValid                    (ElementList list);
  63. static Boolean                     ElementIsValid                            (ElementReference element);
  64. static Boolean                        ElementIsOrphan                        (ElementReference element, Boolean warnUser);
  65. static ElementReference            GetLastElementInChain                (ElementReference firstElement);
  66.  
  67. static Handle                         CloneHandle                                (Handle original);
  68.  
  69. /*****************************************************************************
  70.  * 
  71.  * ElementError                                                            PUBLIC
  72.  * 
  73.  * Retrieves the error generated by the last element-related function called
  74.  * by the client. If no error occured, the result will be zero (noErr).
  75.  *
  76.  *****************************************************************************/
  77. OSErr ElementError(void)
  78. {    
  79.     return fgError;
  80. }
  81.  
  82.  
  83. /*****************************************************************************
  84.  * 
  85.  * CreateElementList                                                    PUBLIC
  86.  * 
  87.  * Call to create a new element list for use by an ad or sub-element list.
  88.  * CreateElementList allocates the list header node and returns it to the
  89.  * caller.
  90.  *
  91.  *****************************************************************************/
  92. ElementList CreateElementList(void)
  93. {
  94.     ElementList    list;
  95.  
  96.  
  97.     list        = (ElementList) NewHandleClear(sizeof(ElementRecord));
  98.     fgError    = MemError();
  99.     
  100.     if ((list == nil) && (fgError == noErr))
  101.         fgError = memFullErr;
  102.     
  103.     if (fgError == noErr)
  104.     {
  105.         fgElementCount++;
  106.  
  107.         if (kLockElementReferences)
  108.             HLockHi((Handle) list);
  109.  
  110.         (**list).structID    = kElementListID;
  111.     }
  112.     else if (list != nil)
  113.     {
  114.         DisposeHandle((Handle)list);
  115.         list = nil;
  116.     }
  117.         
  118.         
  119.     return list;
  120. }
  121.  
  122.  
  123. /*****************************************************************************
  124.  * 
  125.  * CreateElement                                                        PUBLIC
  126.  * 
  127.  * Called to create a new element structure in memory. This function completely
  128.  * initializes the element structure including the creation of an empty
  129.  * sub-element list.
  130.  *
  131.  *****************************************************************************/
  132. ElementReference CreateElement(ElementList list, ElementType type)
  133. {    
  134.     ElementReference    element;
  135.     ElementList            sublist;
  136.     
  137.     
  138.     element    = (ElementReference) NewHandleClear(sizeof (ElementRecord));
  139.     fgError        = MemError();
  140.  
  141.     if ((element == nil) && (fgError == noErr))
  142.         fgError = memFullErr;
  143.     
  144.     
  145.     if (fgError == noErr)
  146.     {
  147.         fgElementCount++;
  148.  
  149.         if (kLockElementReferences == true)
  150.             HLockHi((Handle) element);
  151.  
  152.         (**element).structID            = kElementRecordID;
  153.         (**element).elementNumber    = ++fgElementNumber;
  154.                 
  155.         Insert(list, element);
  156.  
  157.         fgError = CreateElementData(element, type);
  158.         
  159.         if (fgError == noErr)
  160.         {
  161.             sublist = CreateElementList();
  162.             if (fgError == noErr)
  163.                 (**element).subElementList = sublist;
  164.         }
  165.         
  166.         if (fgError != noErr)
  167.         {
  168.             DestroyElement(element);
  169.             element = nil;
  170.         }
  171.     }
  172.     else if (element != nil)
  173.     {
  174.         DisposeHandle((Handle)element);
  175.         element = nil;
  176.     }
  177.  
  178.     return element;
  179. }
  180.  
  181.  
  182. /*****************************************************************************
  183.  * 
  184.  * DestroyElementList                                                   PUBLIC
  185.  * 
  186.  * Called during ad destruction to destroy the entire element list, or during
  187.  * element destruction to destroy the sub-element list.
  188.  *
  189.  * DestroyElementList is a "deep" destory: it will destroy all dynamicData memory
  190.  * associated with every element in the list.
  191.  *
  192.  * • NOTE:    THE SPECIFIED ELEMENT LIST IS INVALID AFTER THIS FUNCTION RETURNS
  193.  *
  194.  *****************************************************************************/
  195. void DestroyElementList(ElementList list)
  196. {
  197.     ElementReference    element;
  198.  
  199.  
  200.     if (ElementListIsValid(list))
  201.     {
  202.         element = GetFirstElement(list);
  203.         while (element != nil)
  204.         {
  205.             DestroyElement(element);
  206.             element = GetFirstElement(list);        
  207.         }
  208.         
  209.         DisposeHandle((Handle)list);
  210.         fgElementCount--;
  211.     }
  212. }
  213.  
  214.  
  215. /*****************************************************************************
  216.  * 
  217.  * DestroyElementRange                                                  PUBLIC
  218.  * 
  219.  * Releases all of the dynamicData memory associated with a range of elements 
  220.  * then releases the elements themselves. This includes the destruction of the
  221.  * any sub-element lists and all of their dynamicData memory.
  222.  *
  223.  * If endElement is nil, then all elements from beginElement to the end of the
  224.  * list will be destroyed.
  225.  *
  226.  * • NOTE:  This can not be used on element chains because DestroyElement()
  227.  *          performs link maintenance on the element list. If the caller orphans
  228.  *          elements to create a chain (of one or more links), then the caller
  229.  *                should use FreeOrphanChain() instead of DestroyElementRange().
  230.  *
  231.  *****************************************************************************/
  232. void DestroyElementRange(ElementReference beginElement, ElementReference endElementOrNil)
  233. {
  234.     ElementReference    element            = beginElement;
  235.     ElementReference    nextElement        = nil;
  236.     
  237.     
  238.     while (element != nil)
  239.     {
  240.         nextElement = GetNextElement(element);
  241.         
  242.         if (element != nil)
  243.             DestroyElement(element);
  244.         
  245.         if (element == endElementOrNil)
  246.             break;
  247.  
  248.         element = nextElement;
  249.     }
  250. }
  251.  
  252.  
  253. /*****************************************************************************
  254.  * 
  255.  * DestroyElement                                                       PUBLIC
  256.  * 
  257.  * Releases all of the dynamicData memory associated with the specified element and
  258.  * then releases the element itself . This includes the destruction of the
  259.  * element’s sub-element list and all of its dynamicData memory.
  260.  *
  261.  * • NOTE: DestroyElement can NOT be used on orphans because of link maintenence!
  262.  *
  263.  *****************************************************************************/
  264. void DestroyElement(ElementReference element)
  265. {
  266.     ElementList        sublist;
  267.     
  268.     
  269.     if (ElementIsValid(element))
  270.     {
  271.         Remove(element);
  272.         
  273.         sublist = GetElementSubElementList(element);
  274.         if (sublist != nil)
  275.             DestroyElementList(sublist);
  276.     
  277.         FreeElementData(element);            
  278.         FreeElement(element);
  279.     }
  280. }
  281.  
  282.  
  283. /*****************************************************************************
  284.  * 
  285.  * CountElements                                                        PUBLIC
  286.  * 
  287.  * Returns the number of elements contained in a specified element list.
  288.  *
  289.  * • NOTE:    This does NOT include the count of any elements that may or may not
  290.  *                be in sub-element lists.
  291.  *
  292.  *****************************************************************************/
  293. short CountElements(ElementList list)
  294. {
  295.     ElementReference    element;
  296.     short                    count;
  297.     
  298.  
  299.     count    = 0;
  300.     
  301.     if (ElementListIsValid(list))
  302.         for (element = GetFirstElement(list); element != nil; element = GetNextElement(element))
  303.             count++;
  304.     
  305.     return count;
  306. }
  307.  
  308.  
  309. /*****************************************************************************
  310.  * 
  311.  * CountElementAllocations                                              PUBLIC
  312.  * 
  313.  * Returns the number of elements allocation
  314.  *
  315.  *****************************************************************************/
  316. unsigned long CountElementAllocations(void)
  317. {
  318.     return fgElementCount;
  319. }
  320.  
  321.  
  322. /*****************************************************************************
  323.  * 
  324.  * GetFirstElement                                                      PUBLIC
  325.  * 
  326.  * Retrieves the first element in an element list (skips the list head).
  327.  * If the list is empty, NIL is returned.
  328.  *
  329.  *****************************************************************************/
  330. ElementReference GetFirstElement(ElementList list)
  331. {
  332.     return ElementListIsValid(list) ? (**list).next : nil;    
  333. }
  334.  
  335.  
  336.  
  337. /*****************************************************************************
  338.  * 
  339.  * GetLastElement                                                       PUBLIC
  340.  * 
  341.  * Find last element in list
  342.  * 
  343.  *****************************************************************************/
  344. ElementReference GetLastElement(ElementList list)
  345. {
  346.     ElementReference    element;
  347.     
  348.  
  349.     element = GetFirstElement(list);                                                        // find the last element in the list
  350.     if (element != nil)                                                                        // while there are more elements in list
  351.         while (GetNextElement(element) != nil)                                            // move forwards in the list
  352.             element = GetNextElement(element);
  353.           
  354.     return element;
  355. }
  356.  
  357.  
  358. /*****************************************************************************
  359.  * 
  360.  * GetNextElement                                                       PUBLIC
  361.  * 
  362.  * Returns the next element reference after a specified element
  363.  *
  364.  *****************************************************************************/
  365. ElementReference GetNextElement(ElementReference element)
  366. {
  367.     return ElementIsValid(element) ? (**element).next : nil;
  368. }
  369.  
  370.  
  371. /*****************************************************************************
  372.  * 
  373.  * GetPreviousElement                                                   PUBLIC
  374.  * 
  375.  * Returns the element previous to a specified element, but ignores the list
  376.  * header. If the specified element is the first "valid" element in the list,
  377.  * then nil is returned.
  378.  *
  379.  *****************************************************************************/
  380. ElementReference GetPreviousElement(ElementReference element)
  381. {
  382.     ElementReference        previous;
  383.  
  384.     previous = nil;
  385.     
  386.     if (ElementIsValid(element))
  387.     {
  388.         previous = (**element).previous;
  389.         if ((**previous).structID == kElementListID)
  390.             previous = nil;
  391.     }
  392.     
  393.     return previous;
  394. }
  395.  
  396.  
  397. /*****************************************************************************
  398.  * 
  399.  * GetElementList                                                       PUBLIC
  400.  * 
  401.  * Returns the element list reference that owns an element. If the element is
  402.  * an orphan (or in an orphaned element chain), nil will be returned.
  403.  * 
  404.  *****************************************************************************/
  405. ElementList GetElementList(ElementReference element)
  406. {
  407.     ElementList        list;
  408.     
  409.     list = nil;
  410.     
  411.     if (ElementIsValid(element))
  412.     {
  413.         while ((element != nil) && ((**element).structID != kElementListID))        // if the element is not the head of the list
  414.             element = (**element).previous;                                                    // then get the previous element and try again
  415.         
  416.         list = element;
  417.     }
  418.         
  419.     return list;
  420. }
  421.  
  422. /*****************************************************************************
  423.  * 
  424.  * GetSubElementList
  425.  * 
  426.  *****************************************************************************/
  427. ElementList GetSubElementList(ElementReference element)
  428. {
  429.     return GetElementSubElementList(element);
  430. }
  431.  
  432. /*****************************************************************************
  433.  * 
  434.  * CloneElementList                                                     PUBLIC
  435.  * 
  436.  * Creates a new element list and populates it with the contents of the specified
  437.  * source element list. Any attached sub-element lists are also cloned. Note that
  438.  * static items such as attached TIFF images are cloned using the Static Item ADT.
  439.  *
  440.  * The two lists will have identical element numbers (and owner numbers for
  441.  * clipping paths).
  442.  *
  443.  *****************************************************************************/
  444. ElementList CloneElementList(ElementList sourceList)
  445. {
  446.     OSErr                    error;
  447.     ElementList         destinationList;
  448.     ElementReference     iterator;
  449.     ElementReference  clone;
  450.     
  451.     error                    = nilHandleErr;
  452.     destinationList    = nil;
  453.     
  454.     if (ElementListIsValid(sourceList))
  455.     {
  456.         destinationList    = CreateElementList();                        // create the new clone list
  457.         error                    = ElementError();                                // did creating it fail?
  458.         
  459.         if (destinationList != nil)
  460.         {
  461.             for (iterator = GetFirstElement(sourceList); iterator != nil; iterator = GetNextElement(iterator))
  462.             {
  463.                 clone    = CloneElement(iterator);                            // clone the element
  464.                 error    = ElementError();                                        // did it fail?
  465.                 
  466.                 if (clone != nil)                                                // if not, insert it in the clone list
  467.                 {                                                                    // and synchronize the element numbers
  468.                     Insert(destinationList, clone);                        // also synchronize clipping paths (if we are supposed to!)
  469.                 }
  470.                 else                                                                // otherwise we need to destroy what
  471.                 {                                                                    // we've already cloned and then
  472.                     DestroyElementList(destinationList);                // return a nil result (and an error
  473.                     destinationList = nil;                                    // via ElementError() to the caller).
  474.                     break;
  475.                 }
  476.             }
  477.     
  478.             
  479.             if (destinationList != nil)
  480.             {
  481.                 (**destinationList).elementNumber = (**sourceList).elementNumber;
  482.             }
  483.         }        
  484.     }
  485.  
  486.     fgError = error;                                                        // be sure to (re)populate this!
  487.     return destinationList;                                                // return resulting list (may be nil!)
  488. }
  489.  
  490.  
  491. /*****************************************************************************
  492.  * 
  493.  * CloneElement                                                         PUBLIC
  494.  *
  495.  * Creates a new element and populates it with the contents of the specified
  496.  * source element including any sub-elements.
  497.  *
  498.  * The cloned element is an orphan and will need to be adopted into a list
  499.  *
  500.  *****************************************************************************/
  501. ElementReference CloneElement(ElementReference element)
  502. {
  503.     ElementReference        clone;
  504.     ElementList                owningList;
  505.     OSErr                        error;
  506.     
  507.     error = nilHandleErr;
  508.     clone    = nil;
  509.     
  510.     if (ElementIsValid(element))
  511.     {
  512.         owningList = GetElementList(element);
  513.         
  514.         if (ElementListIsValid(owningList))
  515.         {
  516.             clone = CreateElement(owningList, GetElementType(element));                                        // try to create the clone element
  517.             error = ElementError();
  518.             
  519.             if (error == noErr)
  520.             {
  521.                 OrphanElement(clone);                                                                            // orphan it        
  522.                 error = CloneElementData(element, clone);                                                    // and copy the original’s data
  523.             }
  524.             
  525.             if (error == noErr)                                                                                    // if there was not an error up above
  526.             {                                                                                                            // then clone sub-element list
  527.                 DisposeHandle((Handle)((**clone).subElementList));                                        // dispose of existing header
  528.                 fgElementCount--;
  529.                 (**clone).subElementList = CloneElementList((**element).subElementList);        // did this fail?
  530.                 error = ElementError();
  531.             }
  532.             
  533.             if (error != noErr)                                                                                    // did something fail?
  534.             {                                                                                                            // if so release this puppy--we’ve failed!
  535.                 FreeOrphanChain(clone);                                                                            // and zero out the return result
  536.                 clone = nil;                                                                                        
  537.             }
  538.         }
  539.     }        
  540.         
  541.     fgError = error;                                                                                                // be sure to (re)populate this correctly
  542.     return clone;                                                                                                    // and return this guy to the caller
  543. }
  544.  
  545. /*****************************************************************************
  546.  * 
  547.  * OrphanElement                                                        PUBLIC
  548.  * 
  549.  * OrphanElement extracts an element from a list. Only the specified element
  550.  * is extracted--the linkages to the next and previous elements in the list
  551.  * are adjusted. Of course if the element has a sub-element list attached to
  552.  * it, the list remains with the orphaned element.
  553.  *
  554.  * When an element is orphaned, the caller takes responsibility for the
  555.  * element - especially its destruction when they are done with it.
  556.  *
  557.  * An orphand can be "adopted" using AdoptOrphan or either of the
  558.  * AdoptOrphanInsertingXXXElement functions. Once this happens, the element is
  559.  * no longer and orphan and the list maintenance code regains responsibilty
  560.  * for managing the element.
  561.  *
  562.  *****************************************************************************/
  563. void OrphanElement(ElementReference element)
  564. {
  565.     if (ElementIsValid(element))
  566.         if (ElementIsOrphan(element, false) == false)
  567.             Remove(element);
  568. }
  569.  
  570.  
  571. /*****************************************************************************
  572.  * 
  573.  * OrphanElementRange                                                   PUBLIC
  574.  * 
  575.  * Like DestroyElementRange, OrphanElementRange operates on a range of elements
  576.  * specified by an element to begin with and an element to end with. Essentially,
  577.  * OrphanElementRange extracts an range of elements by adjusting the links of the
  578.  * neighboring elements.
  579.  *
  580.  * If endElement is nil, then all elements from beginElement to the end of the
  581.  * list will be orphaned.
  582.  *
  583.  * An linked-list of orphaned elements is called a "chain."
  584.  * A "chain" is not an "element list" because it does not have a head node
  585.  * The caller takes responsibility for the elements in the chain
  586.  * - especially their destruction when they are done with them.
  587.  *
  588.  * An  chain can be "adopted" using AdoptOrphan or
  589.  * either of the AdoptOrphanInsertingXXXElement functions. Once this happens, the chain becomes
  590.  * part of a valid list and is no longer orphaned and the list maintenance code
  591.  * regains responsibilty for managing the elements.
  592.  *
  593.  *****************************************************************************/
  594. void OrphanElementRange(ElementReference beginElement, ElementReference endElementOrNil)
  595. {
  596.     ElementReference previous = (**beginElement).previous;
  597.     ElementReference next     = endElementOrNil;
  598.     
  599.     if (endElementOrNil != nil)
  600.     {
  601.         next = GetNextElement(endElementOrNil);
  602.         (**endElementOrNil).next = nil;            // the end of the chain
  603.     }
  604.     
  605.     Link(previous, next);
  606.     (**beginElement).previous = nil;                // the beginning of the chain
  607. }
  608.  
  609.  
  610. /*****************************************************************************
  611.  * 
  612.  * AdoptOrphan                                                                         PUBLIC
  613.  * 
  614.  * AdoptOrphan always appends the specified element to the end of the
  615.  * specified list.
  616.  * This function is quite useful in moving an existing element from one list
  617.  * to another.
  618.  *
  619.  * NOTE:    The specified element may be the first element in a "chain" -
  620.  *       (such as the element range resulting from a call to
  621.  *            OrphanElementRange). Since this function only deals with the
  622.  *            links between the last element in a ElementList and the element specified,
  623.  *            this is not a problem.
  624.  *
  625.  *****************************************************************************/
  626. void AdoptOrphan(ElementList list, ElementReference orphan)
  627. {
  628.     if (ElementIsOrphan(orphan, true))
  629.         Insert(list, orphan);
  630. }
  631.  
  632.  
  633. /*****************************************************************************
  634.  * 
  635.  * AdoptOrphanInsertingBeforeElement                                    PUBLIC
  636.  * 
  637.  * Inserts the specified orphan or chain before the specified element.
  638.  * To insert an element at the end of an element list use AdoptOrphan.
  639.  * See also AdoptOrphanInsertingAfterElement().
  640.  *
  641.  * NOTE:    The orphan may be the first element in a chain, in which case the
  642.  *       entire chain is adopted.
  643.  *
  644.  * SAMPLE USAGE:
  645.  *
  646.  *        element    = GetFirstElement(someList);
  647.  *        orphan    = CloneElement(element);
  648.  *        AdoptOrphanInsertingBeforeElement(orphan, element);
  649.  *
  650.  *****************************************************************************/
  651. void AdoptOrphanInsertingBeforeElement(ElementReference orphan, ElementReference element)
  652. {
  653.     ElementReference    previous;
  654.     ElementReference    last;
  655.     ElementList            list;
  656.  
  657.  
  658.     if (ElementIsOrphan(orphan, true))
  659.     {
  660.         list            = GetElementList(element);
  661.         previous        = (**element).previous;
  662.         last            = GetLastElementInChain(orphan);
  663.  
  664.         Link(previous, orphan);
  665.         Link(last,     element);
  666.     }
  667. }
  668.  
  669.  
  670. /*****************************************************************************
  671.  * 
  672.  * AdoptOrphanInsertingAfterElement                                                    PUBLIC
  673.  * 
  674.  * Inserts the specified orphan or chain after the specified element.
  675.  * To insert an element at the end of an element list use AdoptOrphan.
  676.  * See also AdoptOrphanInsertingBeforeElement().
  677.  *
  678.  * NOTE:    The orphan may be the first element in a chain, in which case the
  679.  *       entire chain is adopted.
  680.  *
  681.  * SAMPLE USAGE:
  682.  *
  683.  *        element    = GetFirstElement(list);
  684.  *        orphan    = CloneElement(element);
  685.  *        AdoptOrphanInsertingAfterElement(orphan, element);
  686.  *
  687.  *****************************************************************************/
  688. void AdoptOrphanInsertingAfterElement(ElementReference orphan, ElementReference element)
  689. {
  690.     ElementReference    next;
  691.     ElementReference    last;
  692.     ElementList            list;
  693.     
  694.  
  695.     if (ElementIsOrphan(orphan, true))
  696.     {
  697.         list    = GetElementList(element);
  698.         next    = GetNextElement(element);
  699.         last    = GetLastElementInChain(orphan);
  700.         
  701.         Link(element, orphan);
  702.         Link(last,    next);
  703.     }    
  704. }
  705.  
  706.  
  707. /*****************************************************************************
  708.  * 
  709.  * FreeOrphanChain                                                                     PUBLIC
  710.  * 
  711.  * Dispose of the elements in an orphan chain
  712.  *
  713.  *****************************************************************************/
  714. void FreeOrphanChain(ElementReference headOfChain)
  715. {
  716.     ElementReference    orphan = headOfChain;
  717.     ElementReference    next   = nil;
  718.     ElementList            sublist;
  719.     
  720.     
  721.     if (ElementIsOrphan(headOfChain, true))
  722.         while (orphan != nil)
  723.         {
  724.             next = GetNextElement(orphan);
  725.     
  726.             sublist = GetElementSubElementList(orphan);
  727.             if (sublist != nil)
  728.                 DestroyElementList(sublist);
  729.                 
  730.             FreeElementData(orphan);
  731.             FreeElement(orphan);
  732.             
  733.             orphan = next;
  734.         }
  735. }
  736.  
  737.  
  738. /*****************************************************************************
  739.  * 
  740.  * CreateElementData                                                   PRIVATE
  741.  * 
  742.  * Populate a newly created element with default data
  743.  *
  744.  * Variables not assigned here will have zero values because new elements
  745.  * are created via NewHandleClear() which zeroes everything out.
  746.  *
  747.  * • NOTE: This function does NOT allocate the element’s sub-element list
  748.  *
  749.  *****************************************************************************/
  750. static OSErr CreateElementData(ElementReference element, ElementType type)
  751. {
  752.     OSErr            error = noErr;        
  753.         
  754.     PopulateElementWithDefaultData(element);
  755.     SetElementType(element, type);
  756.  
  757.     return error;
  758. }
  759.     
  760.  
  761. /*****************************************************************************
  762.  * 
  763.  * CloneElementData                                                    PRIVATE
  764.  * 
  765.  *    Copy all static element data from one to another.
  766.  *
  767.  * If this function fails it is the responsibility of the caller to release
  768.  * any of the memory allocated (usually via a call to FreeOrphanChain())
  769.  *
  770.  * • NOTE: This function does NOT copy the element’s sub-element list
  771.  *
  772.  *****************************************************************************/
  773. static OSErr CloneElementData(ElementReference element, ElementReference clone)
  774. {
  775.     PolyHandle                polygon;
  776.  
  777.     SetElementBoundingBox            (clone,     GetElementBoundingBox(element));
  778.     
  779.     SetElementStrokePenHeight        (clone,     GetElementStrokePenHeight(element));
  780.     SetElementStrokePenWidth        (clone,     GetElementStrokePenWidth(element));
  781.  
  782.     SetElementStrokeColor            (clone,    GetElementStrokeColor(element));
  783.     SetElementFillColor                (clone,     GetElementFillColor(element));
  784.     
  785.     SetElementRoundRectOvalSize    (clone,     GetElementRoundRectOvalSize(element));
  786.     SetElementLineBeginPoint        (clone,  GetElementLineBeginPoint(element));
  787.     SetElementLineEndPoint            (clone,  GetElementLineEndPoint(element));
  788.  
  789.     polygon = GetElementPolygon(element);                                                // do not need to copy the transformed polygon because it will get
  790.     if (polygon != nil)                                                                        // created in SetElementPolygon
  791.         SetElementPolygon(clone, (PolyHandle)CloneHandle((Handle)polygon));
  792.         
  793.     return noErr;
  794. }
  795.  
  796. /*****************************************************************************
  797.  * 
  798.  * FreeElementData                                                     PRIVATE
  799.  * 
  800.  * Dispose of all dynamic memory allocated and stored inside this element.
  801.  *
  802.  * • NOTE: This function does NOT release the element’s sub-element list
  803.  *
  804.  *****************************************************************************/
  805. static void FreeElementData(ElementReference element)
  806. {
  807.     SetElementPolygon(element, nil);
  808. }
  809.  
  810. /*****************************************************************************
  811.  * 
  812.  * FreeElement                                                                PRIVATE
  813.  * 
  814.  * Dispose of the element memory
  815.  *
  816.  *****************************************************************************/
  817. static void FreeElement(ElementReference element)
  818. {
  819.     DisposeHandle((Handle)element);
  820.     fgElementCount--;
  821. }
  822.  
  823. /*****************************************************************************
  824.  * 
  825.  * Insert                                                              PRIVATE
  826.  * 
  827.  * Insert an element into a list, by appending the element to the
  828.  * end of the list
  829.  *
  830.  *****************************************************************************/
  831. static void Insert(ElementList list, ElementReference elementToInsert)
  832. {
  833.     ElementReference element;
  834.     
  835.     
  836.     if (GetFirstElement(list) == nil)
  837.     {
  838.         (**list).next                        = elementToInsert;
  839.         (**elementToInsert).previous    = list;
  840.     }
  841.     else
  842.     {
  843.         element                                = GetLastElement(list);
  844.         (**element).next                    = elementToInsert;
  845.         (**elementToInsert).previous    = element;
  846.     }
  847. }
  848.  
  849.  
  850. /*****************************************************************************
  851.  * 
  852.  * Remove                                                              PRIVATE
  853.  * 
  854.  * Remove an element from the list
  855.  *
  856.  *****************************************************************************/
  857. static void Remove(ElementReference element)
  858. {
  859.     ElementReference    previous        = (**element).previous;
  860.     ElementReference    next          = (**element).next;
  861.  
  862.     Link(previous, next);
  863.  
  864.     (**element).previous = nil;
  865.     (**element).next     = nil;
  866.     
  867. }
  868.  
  869.  
  870. /*****************************************************************************
  871.  * 
  872.  * Link                                                                PRIVATE
  873.  * 
  874.  * Establish a 2-way link between two elements
  875.  *
  876.  * The second element CAN BE nil.
  877.  *
  878.  *****************************************************************************/
  879. static void Link(ElementReference previous, ElementReference next)
  880. {
  881.     (**previous).next = next;
  882.     
  883.     if (next != nil)
  884.         (**next).previous = previous;
  885. }
  886.  
  887.  
  888. /*****************************************************************************
  889.  * 
  890.  * ElementListIsValid                                                   PRIVATE
  891.  * 
  892.  * returns true if specified element is valid. This is useful for debugging.
  893.  *
  894.  *****************************************************************************/
  895. static Boolean ElementListIsValid(ElementList list)
  896. {
  897.     ElementReference head = (ElementReference)list;
  898.     Boolean isValid = (head != nil && ((**head).structID == kElementListID));
  899.     
  900.     Assert(isValid, "ELEMENT ADT: An invalid element list has been detected.");
  901.  
  902.     return isValid;
  903. }
  904.  
  905.  
  906. /*****************************************************************************
  907.  * 
  908.  * ElementIsValid                                                         PRIVATE
  909.  * 
  910.  * returns true if specified element is valid. This is useful for debugging.
  911.  *
  912.  *****************************************************************************/
  913. static Boolean ElementIsValid(ElementReference element)
  914. {
  915.     Boolean isValid = (element != nil && ((**element).structID == kElementRecordID));
  916.     
  917.     Assert(isValid, "ELEMENT ADT: An invalid element has been detected!");
  918.  
  919.     return isValid;
  920. }
  921.  
  922.  
  923. /*****************************************************************************
  924.  * 
  925.  * ElementIsOrphan                                                      PRIVATE
  926.  * 
  927.  * Returns true if specified element is not connected to a list
  928.  *
  929.  *****************************************************************************/
  930. static Boolean ElementIsOrphan(ElementReference element, Boolean warnUser)
  931. {
  932.     Boolean orphaned;
  933.     
  934.     
  935.     orphaned    = false;
  936.  
  937.     if (ElementIsValid(element))
  938.     {
  939.         if ((**element).previous == nil)
  940.             orphaned = true;
  941.  
  942.         if (warnUser)
  943.         {
  944.             Assert(orphaned, "ELEMENT ADT: An invalid orphan has been detected!");
  945.         }
  946.     }    
  947.  
  948.     return orphaned;
  949. }
  950.  
  951.  
  952. /*****************************************************************************
  953.  * 
  954.  * GetLastElementInChain                                               PRIVATE
  955.  * 
  956.  * Retrieves the last orphan in an orphan chain.
  957.  *
  958.  *
  959.  * SAMPLE USAGE:
  960.  *        ElementReference lastOrphan = GetLastElementInChain(firstOrphan);
  961.  *
  962.  *****************************************************************************/
  963. static ElementReference GetLastElementInChain(ElementReference firstElement)
  964. {
  965.     ElementReference lastElement = nil;
  966.     
  967.     if (ElementIsOrphan(firstElement, true))
  968.     {
  969.         lastElement = firstElement;
  970.         while (GetNextElement(lastElement) != nil)
  971.             lastElement = GetNextElement(lastElement);
  972.     }
  973.  
  974.     return lastElement;
  975. }
  976.  
  977. // --------------------------------------------------------------------------
  978.  
  979. #pragma mark -
  980. #pragma mark ACCESSORS
  981. #pragma mark -
  982.  
  983. // --------------------------------------------------------------------------
  984.  
  985. ElementType GetElementType(ElementReference element)
  986. {
  987.     return ElementIsValid(element) ? (**element).elementType : kUnknownElement;
  988. }
  989.  
  990. // --------------------------------------------------------------------------
  991.  
  992. unsigned long GetElementNumber(ElementReference element)
  993. {
  994.     return ElementIsValid(element) ? (**element).elementNumber : -1;
  995. }
  996.  
  997.  
  998. // --------------------------------------------------------------------------
  999.  
  1000. ElementList GetElementSubElementList(ElementReference element)
  1001. {
  1002.     return ElementIsValid(element) ?  (**element).subElementList : nil;
  1003. }
  1004.  
  1005.  
  1006. // --------------------------------------------------------------------------
  1007.  
  1008. Rect GetElementBoundingBox(ElementReference element)
  1009. {
  1010.     return ElementIsValid(element) ? (**element).boundingBox : fgEmptyRect;
  1011. }
  1012.  
  1013. // --------------------------------------------------------------------------
  1014.  
  1015. Point GetElementRoundRectOvalSize(ElementReference element)
  1016. {
  1017.     return ElementIsValid(element) ? (**element).roundRectOvalSize : fgEmptyPoint;
  1018. }
  1019.  
  1020.  
  1021. // --------------------------------------------------------------------------
  1022.  
  1023. Point GetElementLineBeginPoint(ElementReference element)
  1024. {
  1025.     return ElementIsValid(element) ? (**element).line[0] : fgEmptyPoint;
  1026. }
  1027.  
  1028.  
  1029. // --------------------------------------------------------------------------
  1030.  
  1031. Point GetElementLineEndPoint(ElementReference element)
  1032. {
  1033.     return ElementIsValid(element) ? (**element).line[1] : fgEmptyPoint;
  1034. }
  1035.  
  1036.  
  1037. // --------------------------------------------------------------------------
  1038.  
  1039. PolyHandle GetElementPolygon(ElementReference element)
  1040. {
  1041.     return ElementIsValid(element) ? (**element).polygon : nil;
  1042. }
  1043.  
  1044. // --------------------------------------------------------------------------
  1045.  
  1046. RGBColor GetElementFillColor(ElementReference element)
  1047. {
  1048.     RGBColor white = kRGBWhite;
  1049.     
  1050.     return ElementIsValid(element) ? (**element).fillInfo.rgbColor : white;
  1051. }
  1052.  
  1053. // --------------------------------------------------------------------------
  1054.  
  1055. short GetElementStrokePenWidth(ElementReference element)
  1056. {
  1057.     return ElementIsValid(element) ? (**element).strokeInfo.penWidth : 0;
  1058. }
  1059.  
  1060. // --------------------------------------------------------------------------
  1061.  
  1062. short GetElementStrokePenHeight(ElementReference element)
  1063. {
  1064.     return ElementIsValid(element) ? (**element).strokeInfo.penHeight : 0;
  1065. }
  1066.  
  1067. // --------------------------------------------------------------------------
  1068.  
  1069. RGBColor GetElementStrokeColor(ElementReference element)
  1070. {
  1071.     RGBColor black = kRGBBlack;
  1072.     
  1073.     return ElementIsValid(element) ? (**element).strokeInfo.rgbColor : black;
  1074. }
  1075.  
  1076. // --------------------------------------------------------------------------
  1077.  
  1078. #pragma mark -
  1079. #pragma mark MANIPULATORS
  1080. #pragma mark -
  1081.  
  1082. // --------------------------------------------------------------------------
  1083.  
  1084. void SetElementType(ElementReference element, ElementType elementType)
  1085. {
  1086.     if (ElementIsValid(element))
  1087.         (**element).elementType = elementType;
  1088. }
  1089.  
  1090.  
  1091. // --------------------------------------------------------------------------
  1092.  
  1093. void SetElementBoundingBox(ElementReference element, Rect boundingBox)
  1094. {    
  1095.     if (ElementIsValid(element))
  1096.     {
  1097.         (**element).boundingBox    = boundingBox;                                                
  1098.     }
  1099. }
  1100.  
  1101. // --------------------------------------------------------------------------
  1102.  
  1103. void SetElementRoundRectOvalSize(ElementReference element, Point ovalSize)
  1104. {
  1105.     if (ElementIsValid(element))
  1106.         (**element).roundRectOvalSize    = ovalSize;
  1107. }
  1108.  
  1109. // --------------------------------------------------------------------------
  1110.  
  1111. void SetElementLineBeginPoint(ElementReference element, Point p)
  1112. {
  1113.     if (ElementIsValid(element))
  1114.         (**element).line[0]    = p;
  1115. }
  1116.  
  1117. // --------------------------------------------------------------------------
  1118.  
  1119. void SetElementLineEndPoint(ElementReference element, Point p)
  1120. {
  1121.     if (ElementIsValid(element))
  1122.         (**element).line[1]    = p;
  1123. }
  1124.  
  1125. // --------------------------------------------------------------------------
  1126.  
  1127. void SetElementPolygon(ElementReference element, PolyHandle polygon)
  1128. {
  1129.     if (ElementIsValid(element))
  1130.     {
  1131.         if ((**element).polygon != polygon)
  1132.             if ((**element).polygon)
  1133.                 KillPoly((**element).polygon);
  1134.         
  1135.         (**element).polygon = polygon;
  1136.     }    
  1137. }
  1138.  
  1139. // --------------------------------------------------------------------------
  1140.  
  1141. void SetElementFillColor(ElementReference element, RGBColor color)
  1142. {
  1143.     if (ElementIsValid(element))
  1144.             (**element).fillInfo.rgbColor    = color;
  1145. }
  1146.  
  1147. // --------------------------------------------------------------------------
  1148.  
  1149. void SetElementStrokePenWidth(ElementReference element, short penWidth)
  1150. {
  1151.     if (ElementIsValid(element))
  1152.     {
  1153.         (**element).strokeInfo.penWidth         = penWidth;
  1154.     }
  1155. }
  1156.  
  1157. // --------------------------------------------------------------------------
  1158.  
  1159. void SetElementStrokePenHeight(ElementReference element, short penHeight)
  1160. {
  1161.     if (ElementIsValid(element))
  1162.     {
  1163.         (**element).strokeInfo.penHeight         = penHeight;
  1164.     }
  1165. }
  1166.  
  1167. // --------------------------------------------------------------------------
  1168.  
  1169. void SetElementStrokeColor(ElementReference element, RGBColor color)
  1170. {
  1171.     if (ElementIsValid(element))
  1172.             (**element).strokeInfo.rgbColor    = color;
  1173. }
  1174.  
  1175. // --------------------------------------------------------------------------
  1176.  
  1177. /*****************************************************************************
  1178.  * 
  1179.  * CloneHandle
  1180.  * 
  1181.  * Allocates a new handle, copies the original handles contents to the new handle
  1182.  * and returns. The handle states will also be the same (purgeable, locked, etc).
  1183.  * If an error occurs, nil will be returned.
  1184.  *
  1185.  *****************************************************************************/
  1186.  
  1187. static Handle CloneHandle(Handle original)
  1188. {
  1189.     Handle    duplicate;
  1190.     char        state;
  1191.     
  1192.     Assert(original != nil, "invalid handle");
  1193.     
  1194.     duplicate    = original;
  1195.     state            = HGetState(original);
  1196.     
  1197.     HandToHand(&duplicate);
  1198.     
  1199.     if (MemError() == noErr)
  1200.     {
  1201.         HSetState(original, state);        // just to make sure the toolbox didn't screw this up
  1202.  
  1203.         if (((unsigned short) state) & 0x0080)
  1204.             HLock(duplicate);
  1205.  
  1206.         if (((unsigned short) state) & 0x0040)
  1207.             HPurge(duplicate);
  1208.     }
  1209.     else
  1210.     {
  1211.         duplicate = nil;
  1212.     }
  1213.     
  1214.     return duplicate;
  1215. }
  1216.  
  1217.  
  1218.  
  1219.  
  1220.  
  1221.